package main;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Properties;
import java.util.Random;
import java.util.Vector;

public class SubseqClustering {
	MySqlConnect mysql;

	public SubseqClustering(MySqlConnect mysql_) {
		this.mysql = mysql_;
	}

	public HashSet<Subseq> importData(String tablename, String att, int m)
			throws SQLException {
		HashSet<Subseq> map = new HashSet<Subseq>();
		Statement s = mysql.getStatement();
		String query = "select count(*) as size from " + tablename + ";";
		s.execute(query);
		ResultSet rs = s.getResultSet();
		int size = 0;
		if (rs.next())
			size = rs.getInt("size");

		for (int i = 0; i < size - m; i++) {
			Subseq sub = getSubseq(tablename, att, m, i);
			sub.normalize();
			map.add(sub);
		}
		return map;

	}

	public void Kmeans(HashSet<Subseq> set, int k) {
		Vector<HashSet<Subseq>> clusters = new Vector<HashSet<Subseq>>();
		for (int i = 0; i < k; i++) {
			clusters.add(new HashSet<Subseq>());
		}
		Vector<Subseq> centroids = chooseRandomCentroids(set, k);

		boolean changed = true;
		int li = 0;
		while (changed) {
			clusters = new Vector<HashSet<Subseq>>();
			for (int i = 0; i < k; i++) {
				clusters.add(new HashSet<Subseq>());
			}
			Iterator<Subseq> iter = set.iterator();
			while (iter.hasNext()) {
				Subseq next = (Subseq) iter.next();
				ArrayList<Double> distances = new ArrayList<Double>();
				int min = -1;
				for (int i = 0; i < centroids.size(); i++) {
					distances.add(next.stsDistance(centroids.get(i)));
					// System.out.println("distance: " + next + " - "
					// + next.distance(centroids.get(i)) + "\n");
					if (next.equals(centroids.get(i)))
						min = i;
				}
				// System.out.println(distances);
				if (min == -1)
					min = distances.indexOf(Collections.min(distances));

				clusters.get(min).add(next);
			}
			changed = recountCentroids(centroids, clusters);
			saveClusters(centroids, clusters);
			for (int i = 0; i < k; i++) {
				System.out.println(i + " -ty klaster, \ncentroid:"
						+ centroids.get(i) + "\nelementy:\n"
						+ clusters.get(i).size());
//				for (Subseq el : clusters.get(i)) {
//					System.out.println(el + "dist: ");
//					for (int m = 0; m < k; m++) {
//						System.out.print(centroids.get(m).stsDistance(el)
//								+ " - ");
//					}
//					System.out.println("\n");
//				}
//				System.out.println("");

			}
			System.out.println("///////////////////////////////////////////");
			li++;
			// if (li>2) changed = false;
		}
	}

	private void saveClusters(Vector<Subseq> centroids,
			Vector<HashSet<Subseq>> clusters) {

		Statement s = mysql.getStatement();
		// String query = "create"

	}

	private boolean recountCentroids(Vector<Subseq> centroids,
			Vector<HashSet<Subseq>> clusters) {
		boolean changed = false;
		for (int i = 0; i < centroids.size(); i++) {
			Subseq avg = new Subseq(clusters.get(i));
//			HashSet<Subseq> set = clusters.get(i);
//			Object[] set_ar = clusters.get(i).toArray();
//			ArrayList<Double> distances = new ArrayList<Double>();
//			for (int k = 0; k < set_ar.length; k++) {
//				distances.add(((Subseq) set_ar[k]).distance(avg));
//			}
//			// System.out.println(distances);
//			int min = distances.indexOf(Collections.min(distances));
//			avg = (Subseq) set_ar[min];
			if (!avg.equals(null)
					&& !centroids.get(i).getMatrix().equals(avg.getMatrix())) {
				centroids.set(i, avg);
				changed = true;
			}
		}
		return changed;
	}

	private Vector<Subseq> chooseRandomCentroids(HashSet<Subseq> set, int k) {
		Vector<Subseq> centroids = new Vector<Subseq>();
		Random rand = new Random(System.currentTimeMillis());
		ArrayList<Integer> ar = new ArrayList<Integer>();
		int r;
		for (int i = 0; i < k; ++i) {
			do
				r = rand.nextInt(set.size());
			while (ar.contains(r));
			ar.add(r);

		}
		for (int el : ar)
			centroids.add((Subseq) set.toArray()[el]);
		return centroids;
	}

	private Subseq getSubseq(String tablename, String att, int m, int lastId) {
		Statement s = mysql.getStatement();
		String query = "select id, date, periodId, " + att + " from "
				+ tablename + " order by id asc limit 1";
		ResultSet rs;
		ResultSetMetaData rsm;
		int cc = 0;
		try {
			s.execute(query);
			rs = s.getResultSet();
			rsm = rs.getMetaData();
			cc = rsm.getColumnCount() + 1;
		} catch (SQLException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

		query = "select id, date, periodId, " + att
				+ ", concat(date,' ', sec_to_time(periodId*120)) as time from "
				+ tablename + " where id > " + lastId
				+ " order by id asc limit " + m + ";";
		// System.out.println(query);
		double[][] ar = new double[m][cc - 4];
		double[][] arw = new double[m - 1][cc - 4];
		try {
			s.execute(query);
			rs = s.getResultSet();
			ArrayList<Integer> taken = new ArrayList<Integer>();
			int k = 0;
			int begin = -1;
			while (rs.next()) {

				for (int i = 4; i < cc; i++) {
					ar[k][i - 4] = rs.getInt(i);
				}
				taken.add(rs.getInt("id"));
				if (k == 0) {
					begin = rs.getInt("id");
				}
				// if (k > 0)
				// for (int i = 0; i < cc - 4; i++) {
				// arw[k - 1][i] = ar[k][i] / ar[k - 1][i];
				// }
				k++;
			}

			return new Subseq(begin, ar);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;

	}

	public static void main(String[] args) {
		String path = "";
		Properties configFile = new Properties();
		try {
			configFile.load(new FileInputStream(path + "config.properties"));

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		String mysqlhost = configFile.getProperty("mysqlhost");
		String mysqlbasename = configFile.getProperty("mysqlbasename");
		String mysqlusername = configFile.getProperty("mysqlusername");
		String mysqlpassword = configFile.getProperty("mysqlpassword");

		MySqlConnect mysql = new MySqlConnect(mysqlhost, mysqlbasename,
				mysqlusername, mysqlpassword);

		SubseqClustering s = new SubseqClustering(mysql);
		try {
			HashSet<Subseq> set = s.importData("global_aggregation", "size", 5);
			s.Kmeans(set, 10);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
}
